﻿using System;
using System.IO;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using Utils.Weixin.Pay.Options;

namespace Utils.Weixin.Pay.Http
{
    internal class HttpApiV3Handler : DelegatingHandler
    {
        private readonly string merchantId;

        private readonly string serialNo;

        private readonly RSACryptoServiceProvider rsaCryptoServiceProvider;
        public HttpApiV3Handler(WeChatPayOptions options)
        {
            InnerHandler = new HttpClientHandler()
            {
            };
            this.merchantId = options.MerchantNo;
            this.serialNo = options.SerialNumber;
            rsaCryptoServiceProvider = new RSACryptoServiceProvider();
            if (options.PrivateKey.StartsWith("-----BEGIN PRIVATE KEY-----"))
            {
                rsaCryptoServiceProvider.ImportPkcs8PrivateKey(Convert.FromBase64String(RSAFromPkcs8.ExtractFromPemFormat(options.PrivateKey)), out _);
            }
            else
            {
                rsaCryptoServiceProvider.ImportPkcs8PrivateKey(Convert.FromBase64String(options.PrivateKey), out _);
            }

        }
        protected async override Task<HttpResponseMessage> SendAsync(
       HttpRequestMessage request,
       CancellationToken cancellationToken)
        {

            var auth = await BuildAuthAsync(request);
            string value = $"WECHATPAY2-SHA256-RSA2048 {auth}";
            request.Headers.Add("Authorization", value);
            request.Headers.Add("Accept", "application/json");//如果缺少这句代码就会导致下单接口请求失败，报400错误（Bad Request）
            request.Headers.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");//如果缺少这句代码就会导致下单接口请求失败，报400错误（Bad Request）
            return await base.SendAsync(request, cancellationToken);
        }

        protected async Task<string> BuildAuthAsync(HttpRequestMessage request)
        {
            string method = request.Method.ToString();
            string body = "";
            if (method == "POST" || method == "PUT" || method == "PATCH")
            {
                var content = request.Content;
                if (content is MultipartFormDataContent multipartForm)
                {
                 //   var str = await multipartForm.ReadAsStringAsync();
                    foreach (var item in multipartForm)
                    {
                        if (item is JsonContent)
                        {
                            body = await item.ReadAsStringAsync();
                        }
                    }
                }
                else
                {
                    body = await content.ReadAsStringAsync();
                }
            }
            string uri = request.RequestUri.PathAndQuery;
            var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
            string nonce = StringHelper.RadomFileName();
            string message = $"{method}\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
            string signature = Sign(message);
            Console.WriteLine("message："+message);
            Console.WriteLine("signature："+signature);
            return $"mchid=\"{merchantId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{serialNo}\",signature=\"{signature}\"";
        }

        private string Sign(string message)
        {
            byte[] data = Encoding.UTF8.GetBytes(message);
            return Convert.ToBase64String(rsaCryptoServiceProvider.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
        }
    }
}
